package com.ym.paas.config;

import com.ym.paas.dto.Result;
import com.ym.paas.enums.ResultCodeBase;
import com.ym.paas.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.ServletException;
import javax.validation.ValidationException;

/**
 * 统一异常处理
 *
 * @author zetor
 * @date 9.5
 */
@ControllerAdvice
@ResponseBody
public class UnifyExceptionHandler {

    private static Logger logger = LoggerFactory.getLogger(UnifyExceptionHandler.class);

    /**
     * 202 - 操作数据库通用异常
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(DataAccessException.class)
    public Result<String> DataAccessExceptionException(DataAccessException e) {
        logger.error("数据库异常:", e);
        return Result.err(ResultCodeBase.C0000002);
    }

    /**
     * 202 - 操作数据库出现异常:名称重复，外键关联
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(DataIntegrityViolationException.class)
    public Result<String> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        logger.error("数据库约束异常:", e);
        return Result.err(ResultCodeBase.C0000003);
    }

    /**
     * 202 - ServletException
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(ServletException.class)
    public Result<String> handleServletException(ServletException e) {
        logger.error("Servlet请求异常", e);
        return Result.err(ResultCodeBase.C0000007);
    }

    /**
     * 202 - Exception
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(Exception.class)
    public Result<String> handleException(Exception e) {
        logger.error("异常", e);
        return Result.err(ResultCodeBase.C0000005);
    }

    /**
     * 202 - ValidationException
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(ValidationException.class)
    public Result<String> handleValidationException(ValidationException e) {
        logger.error("参数验证异常", e);
        return Result.err(ResultCodeBase.C0000004, e.getMessage());
    }

    /**
     * 202 - HttpMessageNotReadableException
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        logger.error("参数解析异常", e);
        return Result.err(ResultCodeBase.C0000006, e.getMessage());
    }

    /**
     * 202 - BindException
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(BindException.class)
    public Result<String> handleBindException(BindException e) {
        logger.error("参数绑定失败", e);
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String field = error.getField();
        String code = error.getDefaultMessage();
        String message = String.format("%s:%s", field, code);
        return Result.err(ResultCodeBase.C0000004, message);
    }

    /**
     * 202 - MethodArgumentNotValidException
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleArgsException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
        logger.error("参数验证失败: " + message);
        return Result.err(ResultCodeBase.C0000004, message);
    }

    /**
     * 202 - ServiceException Error
     */
    @ResponseStatus(HttpStatus.ACCEPTED)
    @ExceptionHandler(ServiceException.class)
    public Result<String> handleServiceException(ServiceException e) {
        logger.error("业务逻辑异常", e);
        return Result.err(ResultCodeBase.BIZ00001, e.getMessage());
    }

}
